package com.xhb.campusservices.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class JWTUtils {
    // 签名密钥
    private static final String SECRET = "!BIAO@BIAO$";
    private static final Logger logger = LoggerFactory.getLogger(JWTUtils.class);

    /**
     * 生成token
     *
     * @param payload token携带的信息
     * @return token字符串
     */
    public static String getToken(Map<String, String> payload) {
        try {
            // 指定token过期时间为3天
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.DATE, 3);
            JWTCreator.Builder builder = JWT.create();
            // 构建payload
            payload.forEach((k, v) -> builder.withClaim(k, v));
            // 指定过期时间和签名算法
            String token = builder.withExpiresAt(calendar.getTime()).sign(Algorithm.HMAC256(SECRET));
            return token;
        } catch (Exception e) {
            logger.warn("生成JWT失败！{}", e.getMessage());
            return null;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @param token token
     * @return token中包含的用户名
     */
    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("userName").asString();
        } catch (JWTDecodeException e) {
            logger.warn("解密JWT失败！{}", e.getMessage());
            return null;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @param token token
     * @return token中包含的Id
     */
    public static String getUserId(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("userId").asString();
        } catch (JWTDecodeException e) {
            logger.warn("解密JWT失败！{}", e.getMessage());
            return null;
        }
    }

    /**
     * 解析token
     *
     * @param token token字符串
     * @return 解析后的token
     */
    public static DecodedJWT decode(String token) {
        try {
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
            DecodedJWT decodedJWT = jwtVerifier.verify(token);
            return decodedJWT;
        } catch (Exception e) {
            logger.warn("校验JWT失败！{}", e.getMessage());
            return null;
        }

    }

    /**
     * 更新令牌
     *
     * @param token
     * @return
     */
    public static String updateToken(String token) {
        Map<String, String> map = new HashMap<>();
        try {
            //获取旧令牌的信息，并更新到新令牌去
            map.put("userId", JWTUtils.getUserId(token));
            map.put("userName", JWTUtils.getUsername(token));
        } catch (Exception e) {
            logger.warn("更新令牌失败！{}", e.getMessage());
            return null;
        }
        //返回新令牌
        return JWTUtils.getToken(map);
    }

    /**
     * 把令牌时间刷新为0
     *
     * @param token
     * @return
     */
    public static String delToken(String token) {
        Map<String, String> map = new HashMap<>();
        try {
            //获取旧令牌的信息，并更新到新令牌去
            map.put("userId", JWTUtils.getUserId(token));
            map.put("userName", JWTUtils.getUsername(token));
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.SECOND, 0);
            JWTCreator.Builder builder = JWT.create();
            // 构建payload
            map.forEach((k, v) -> builder.withClaim(k, v));
            // 指定过期时间和签名算法
            return builder.withExpiresAt(calendar.getTime()).sign(Algorithm.HMAC256(SECRET));
        } catch (Exception e) {
            logger.warn("刷新令牌失败！{}", e.getMessage());
            return null;
        }
    }

    /**
     * 校验token是否过期
     *
     * @param token
     * @return
     */
    public static boolean isExpire(String token) {
        DecodedJWT jwt = JWT.decode(token);
        //获取时间戳，当前时间戳如果大于jwt.getExpiresAt().getTime()，则过期
        return jwt.getExpiresAt().getTime() < new Date().getTime();
    }

}

